# 二级制的概念
# 1.最高位是符号位 0表示正数1表示负数
# 比如 0110 1100 一般二进制是32位
# 源码的计算方式时除二取余,比如int 类型占4个字节，一个字节是8位，因此占需要有32位
#  比如 int n = 3;  此时n的源码就是 00000000 00000000 00000000 00000011 这就是n的源码
#  左边第一位是符号位 0表示正 1表示负
#  正数的源码，反码，补码，都相同
# int n1= -3; 此时n1的源码是 10000000 00000000 00000000 00000011 这就是 n1的源码
# 反码=源码符号位不变，按位取反 就变成了 11111111 11111111 11111111 11111100
#  因为是二进制的运算 是满二进一 因此在源码的基础上加一就变成了 11111111 11111111 11111111 11111101 这
# 2.正数的原码，反码，补码都一样(三码合一)
# 3.负数的反码=它的原码符号位不变，其它位取反(0->1，1->0)
# 4.负数的补码=它的反码+1，负数的反码=负数的补码-1
# 5.0的反码，补码都是0
# 6.java没有无符号数，换言之，java中的数都是有符号的
# 7.在计算机运算的时候，都是以补码的方式来运算的.
# 8.当我们看运算结果的时候，要看他的原码
# 重点
# 在计算机运算的时候，都是以补码的方式来运算的.
# 当我们看运算结果的时候，要看他的原码
# 位运算符
# python中有6个位运算(&、|、^、~、>>、<<)
# 分别是 按位与&、按位或|、按位异或^，按位取反~，
# 它们的运算规则是
# ：按位与& 两位全为1，结果为1，否则为0
# 按位或| 两位有一个为1，结果为1，否则为0
# 按位异或 ^相同为0，相异为1
# 按位取反~ 1变0    0变1
"""
        //举例
        int a = 2;
        int b = 3;
        System.out.println(a & b);// 2
        //首先我们要先得到2 和 的源码 因为他们都是正数所以源码反码补码都相同，因此只需要计算一个就可以了
        //2的源码  00000000 00000000 00000000 00000010
        //3的源码  00000000 00000000 00000000 00000011
        //按位与 的规则是 ，两位全为1，结果为1，否则为0 因此，得到的结果是
        //        00000000 00000000 00000000 00000010 （这就是按位与之后的结果） 前面我们说过，计算机在运算时是看补码，但是运算结果时看的时源码，因此我们还需要
        //将得到的二进制转换成源码，因为我们是整数，所以原反补都相同，因此无需转换，最终的结果就是2

        //如果是负数的情况
        int c = -3;
        //-3的源码  10000000 00000000 00000000 00000011
        //-3的反码  11111111 11111111 11111111 11111100
        //-3的补码  11111111 11111111 11111111 11111101
        System.out.println(a & c); // 0
        //因为我们上面说过，计算机在运算时，看的是补码，所以先得到补码
        //2的补码是  00000000 00000000 00000000 00000010
        //-3的补码是 11111111 11111111 11111111 11111101
        //          00000000 00000000 0000000 00000000 这就是按位与之后的结果是补码，在装换成源码最终结果是0


        System.out.println(a | c);
        //按位或| 两位有一个为1，结果为1，否则为0
        //2的补码   00000000 00000000 00000000 00000010
        //-3的补码  11111111 11111111 11111111 11111101
        //         11111111 11111111 11111111 11111111 这是按位或之后的补码
        //转换成反码 反码=补码-1 11111111 11111111 11111111 11111110
        //     源码=符号位不变反码按位取反 10000000 00000000 00000000 00000001
        //所以结果是 -1

        System.out.println(a ^ c);//-1
        //按位异或 ^相同为0，相异为1
        //2的补码   00000000 00000000 00000000 00000010
        //-3的补码  11111111 11111111 11111111 11111101
        //所以结果是  111111111 11111111 11111111 11111111 这是按位异或后的补码
        //转换成反码 反码=补码-1 11111111 11111111 11111111 11111110
        //     源码=符号位不变反码按位取反 10000000 00000000 00000000 00000001
        //所以结果是 -1

        System.out.println(~a);//-3
        //按位取反~ 1变0    0变1
        //首先我们要先得到2 和 的源码 因为他们都是正数所以源码反码补码都相同，因此只需要计算一个就可以了
        //2的源码  00000000 00000000 00000000 00000010
        //2的反码  00000000 00000000 00000000 00000010
        //2的补码  00000000 00000000 00000000 00000010

        //按位取反 11111111 11111111 11111111 11111101 这是按位取反之后的补码
        //反码等于 11111111 11111111 11111111 11111100
        //源码等于 10000000 00000000 00000000 00000011  所以结果是-3
"""
# << 左移 规则 符号位不变，高位丢弃低位补0
# 5的源码 00000101
# 因为符号为不动 左移一位得到的是 00001010
# 注意此时还是补码 因为符号为是0 是正数因为正数源码反码补码都相同所以结果是10
print(5 << 1)  # 本质等于 1左移1位表示 5*2 移动几位乘几个2

# >> 右移 规则 符号位不变，低位丢弃，高位补符号位
# 本质就是右移几位除几个2并且是向下取整
# 5的源码 00000101
# 因为符号为不动 右移一位得到的是 00000010
# 注意此时还是补码 因为符号为是0 是正数因为正数源码反码补码都相同所以结果是2
print(5 >> 1)  # 2
